﻿using CsvHelper;
using FlowmeterUI.Models;
using Newtonsoft.Json;
using NLog;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Legends;
using OxyPlot.Series;
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FlowmeterUI.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        #region 变量
        private static Logger logger = LogManager.GetCurrentClassLogger();
        SystemParam systemParam;
        SXJ.Mysql mysql;
        object plotModelLockObject = new object();
        #endregion
        #region 属性
        private string _title = "江东科技流量计项目";
        public string Title
        {
            get { return _title; }
            set { SetProperty(ref _title, value); }
        }
        private string version = "1.5";
        public string Version
        {
            get { return version; }
            set { SetProperty(ref version, value); }
        }
        private bool serialPortState;
        public bool SerialPortState
        {
            get { return serialPortState; }
            set { SetProperty(ref serialPortState, value); }
        }
        private bool remoteFilePathState;
        public bool RemoteFilePathState
        {
            get { return remoteFilePathState; }
            set { SetProperty(ref remoteFilePathState, value); }
        }
        private bool dataBaseState;
        public bool DataBaseState
        {
            get { return dataBaseState; }
            set { SetProperty(ref dataBaseState, value); }
        }
        private string realTimePageVisibility = "Visible";
        public string RealTimePageVisibility
        {
            get { return realTimePageVisibility; }
            set { SetProperty(ref realTimePageVisibility, value); }
        }
        private string parameterPageVisibility = "Collapsed";
        public string ParameterPageVisibility
        {
            get { return parameterPageVisibility; }
            set { SetProperty(ref parameterPageVisibility, value); }
        }
        private string historyPageVisibility = "Collapsed";
        public string HistoryPageVisibility
        {
            get { return historyPageVisibility; }
            set { SetProperty(ref historyPageVisibility, value); }
        }
        private double instantFlow;
        public double InstantFlow
        {
            get { return instantFlow; }
            set { SetProperty(ref instantFlow, value); }
        }
        private double instantVelocity;
        public double InstantVelocity
        {
            get { return instantVelocity; }
            set { SetProperty(ref instantVelocity, value); }
        }
        private double accumulateFlow;
        public double AccumulateFlow
        {
            get { return accumulateFlow; }
            set { SetProperty(ref accumulateFlow, value); }
        }
        private double temperature;
        public double Temperature
        {
            get { return temperature; }
            set { SetProperty(ref temperature, value); }
        }
        private PlotModel plotModel1 = new PlotModel { Title = "瞬时流量", TitleColor = OxyColors.Blue };
        public PlotModel PlotModel1
        {
            get { return plotModel1; }
            set { SetProperty(ref plotModel1, value); }
        }

        private PlotModel plotModel2 = new PlotModel { Title = "瞬时流速", TitleColor = OxyColors.Blue };
        public PlotModel PlotModel2
        {
            get { return plotModel2; }
            set { SetProperty(ref plotModel2, value); }
        }

        private DateTime createTime;
        public DateTime CreateTime
        {
            get { return createTime; }
            set { SetProperty(ref createTime, value); }
        }
        private string remoteFilePath;
        public string RemoteFilePath
        {
            get { return remoteFilePath; }
            set { SetProperty(ref remoteFilePath, value); }
        }
        private DateTime selectStartTime;
        public DateTime SelectStartTime
        {
            get { return selectStartTime; }
            set { SetProperty(ref selectStartTime, value); }
        }
        private DateTime selectEndTime;
        public DateTime SelectEndTime
        {
            get { return selectEndTime; }
            set { SetProperty(ref selectEndTime, value); }
        }
        private bool selectRecordButtonIsEnabled = true;
        public bool SelectRecordButtonIsEnabled
        {
            get { return selectRecordButtonIsEnabled; }
            set { SetProperty(ref selectRecordButtonIsEnabled, value); }
        }
        private int airSelectedIndex = 0;
        public int AirSelectedIndex
        {
            get { return airSelectedIndex; }
            set { SetProperty(ref airSelectedIndex, value); }
        }
        private PlotModel historyInstantFlowPlotModel;
        public PlotModel HistoryInstantFlowPlotModel
        {
            get { return historyInstantFlowPlotModel; }
            set { SetProperty(ref historyInstantFlowPlotModel, value); }
        }
        private PlotModel historyInstantVelocityPlotModel;
        public PlotModel HistoryInstantVelocityPlotModel
        {
            get { return historyInstantVelocityPlotModel; }
            set { SetProperty(ref historyInstantVelocityPlotModel, value); }
        }
        private PlotModel historyAccumulateFlowPlotModel;
        public PlotModel HistoryAccumulateFlowPlotModel
        {
            get { return historyAccumulateFlowPlotModel; }
            set { SetProperty(ref historyAccumulateFlowPlotModel, value); }
        }
        private PlotModel historyInstantTemperaturePlotModel;
        public PlotModel HistoryInstantTemperaturePlotModel
        {
            get { return historyInstantTemperaturePlotModel; }
            set { SetProperty(ref historyInstantTemperaturePlotModel, value); }
        }
        private int airComboBoxSelectedIndex;
        public int AirComboBoxSelectedIndex
        {
            get { return airComboBoxSelectedIndex; }
            set { SetProperty(ref airComboBoxSelectedIndex, value); }
        }
        private AirKind air;
        public AirKind Air
        {
            get { return air; }
            set { SetProperty(ref air, value); }
        }
        private int exportRecordMode = 0;
        public int ExportRecordMode
        {
            get { return exportRecordMode; }
            set { SetProperty(ref exportRecordMode, value); }
        }
        private ObservableCollection<ScaleItem> scaleItems;
        public ObservableCollection<ScaleItem> ScaleItems
        {
            get { return scaleItems; }
            set { SetProperty(ref scaleItems, value); }
        }
        #endregion
        #region 方法绑定
        private DelegateCommand appLoadedEventCommand;
        public DelegateCommand AppLoadedEventCommand =>
            appLoadedEventCommand ?? (appLoadedEventCommand = new DelegateCommand(ExecuteAppLoadedEventCommand));
        private DelegateCommand appClosedEventCommand;
        public DelegateCommand AppClosedEventCommand =>
            appClosedEventCommand ?? (appClosedEventCommand = new DelegateCommand(ExecuteAppClosedEventCommand));
        private DelegateCommand<object> menuCommand;
        public DelegateCommand<object> MenuCommand =>
            menuCommand ?? (menuCommand = new DelegateCommand<object>(ExecuteMenuCommand));
        private DelegateCommand<object> filePathSelectCommand;
        public DelegateCommand<object> FilePathSelectCommand =>
            filePathSelectCommand ?? (filePathSelectCommand = new DelegateCommand<object>(ExecuteFilePathSelectCommand));
        private DelegateCommand saveParamCommand;
        public DelegateCommand SaveParamCommand =>
            saveParamCommand ?? (saveParamCommand = new DelegateCommand(ExecuteSaveParamCommand));
        private DelegateCommand<object> selectRecordCommand;
        public DelegateCommand<object> SelectRecordCommand =>
            selectRecordCommand ?? (selectRecordCommand = new DelegateCommand<object>(ExecuteSelectRecordCommand));
        private DelegateCommand<object> exportRecordCommand;
        public DelegateCommand<object> ExportRecordCommand =>
            exportRecordCommand ?? (exportRecordCommand = new DelegateCommand<object>(ExecuteExportRecordCommand));
        private DelegateCommand airComboBoxSelectionChangedEventCommand;
        public DelegateCommand AirComboBoxSelectionChangedEventCommand =>
            airComboBoxSelectionChangedEventCommand ?? (airComboBoxSelectionChangedEventCommand = new DelegateCommand(ExecuteAirComboBoxSelectionChangedEventCommand));
        private DelegateCommand<object> exportRecordModeCommand;
        public DelegateCommand<object> ExportRecordModeCommand =>
            exportRecordModeCommand ?? (exportRecordModeCommand = new DelegateCommand<object>(ExecuteExportRecordModeCommand));

        void ExecuteExportRecordModeCommand(object obj)
        {
            ExportRecordMode = int.Parse(obj.ToString());
        }
        void ExecuteAirComboBoxSelectionChangedEventCommand()
        {
            try
            {
                Air.Name = systemParam.AirArray[AirComboBoxSelectedIndex];
                Air.State = true;
                lock (plotModelLockObject)
                {
                    var s = (LineSeries)PlotModel1.Series[0];
                    s.Points.Clear();
                    PlotModel1.InvalidatePlot(true);
                    s = (LineSeries)PlotModel2.Series[0];
                    s.Points.Clear();
                    PlotModel2.InvalidatePlot(true);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                logger.Error(ex);
            }

        }
        async void ExecuteExportRecordCommand(object obj)
        {
            int airkind;
            switch (AirSelectedIndex)
            {
                case 1:
                    airkind = 2;
                    break;
                case 0:
                default:
                    airkind = 1;
                    break;
            }
            switch (obj.ToString())
            {
                case "0":
                    {
                        SelectRecordButtonIsEnabled = false;
                        await Task.Run(() =>
                        {
                            var mysql1 = new SXJ.Mysql(systemParam.MysqlIp);
                            if (mysql1.Connect())
                            {
                                try
                                {
                                    List<Record> list = new List<Record>();
                                    int _count = 0;
                                    DateTime dt1 = SelectStartTime;
                                    do
                                    {
                                        string str = $"SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'flowmeter{SelectStartTime.AddMonths(_count).ToString("yyyyMM")}';";
                                        DataSet ds = mysql1.Select(str);
                                        DataTable dt = ds.Tables[0];
                                        if (Convert.ToInt32(dt.Rows[0][0]) == 1)
                                        {
                                            str = $"SELECT * FROM flowmeter{SelectStartTime.AddMonths(_count).ToString("yyyyMM")} WHERE airkind = {airkind} AND created >= '{SelectStartTime:yyyy-MM-dd HH:mm:ss}' AND created <= '{SelectEndTime:yyyy-MM-dd HH:mm:ss}' ORDER BY created ASC";
                                            ds = mysql1.Select(str);
                                            dt = ds.Tables[0];
                                            if (dt.Rows.Count > 0)
                                            {

                                                for (int i = 0; i < dt.Rows.Count; i++)
                                                {
                                                    var _dt0 = Convert.ToDateTime(dt.Rows[i]["created"]);
                                                    switch (ExportRecordMode)
                                                    {
                                                        case 0:
                                                            {
                                                                if ((_dt0 - dt1).TotalHours > 1)
                                                                {
                                                                    dt1 = _dt0;
                                                                }
                                                            }
                                                            break;
                                                        case 1:
                                                            {
                                                                if ((_dt0 - dt1).TotalHours > 12)
                                                                {
                                                                    dt1 = _dt0;
                                                                }
                                                            }
                                                            break;
                                                        case 2:
                                                            {
                                                                if ((_dt0 - dt1).TotalHours > 24)
                                                                {
                                                                    dt1 = _dt0;
                                                                }
                                                            }
                                                            break;
                                                        default:
                                                            
                                                            break;
                                                    }
                                                    if (_dt0 >= dt1)
                                                    {
                                                        list.Add(new Record
                                                        {
                                                            瞬时流量 = Convert.ToDouble(dt.Rows[i]["instantflow"]),
                                                            瞬时流速 = Convert.ToDouble(dt.Rows[i]["instantvelocity"]),
                                                            累积流量 = Convert.ToDouble(dt.Rows[i]["accumulateflow"]),
                                                            温度 = Convert.ToDouble(dt.Rows[i]["instanttemperature"]),
                                                            时间 = Convert.ToDateTime(dt.Rows[i]["created"]),
                                                            气体类型 = Convert.ToInt32(dt.Rows[i]["airkind"])
                                                        });
                                                        switch (ExportRecordMode)
                                                        {
                                                            case 0:
                                                                {
                                                                    var _dt1 = dt1.AddHours(1);
                                                                    dt1 = new DateTime(_dt1.Year, _dt1.Month, _dt1.Day, _dt1.Hour, 0, 0);
                                                                }                                                                
                                                                break;
                                                            case 1:
                                                                {
                                                                    var _dt1 = dt1.AddHours(12);
                                                                    dt1 = new DateTime(_dt1.Year, _dt1.Month, _dt1.Day, _dt1.Hour, 0, 0);
                                                                }
                                                                break;
                                                            case 2:
                                                                {
                                                                    var _dt1 = dt1.AddHours(24);
                                                                    dt1 = new DateTime(_dt1.Year, _dt1.Month, _dt1.Day, _dt1.Hour, 0, 0);
                                                                }
                                                                break;
                                                            default:
                                                                //dt1 = Convert.ToDateTime(dt.Rows[i]["created"]);
                                                                break;
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        _count++;
                                    } while (SelectEndTime.Year * 12 + SelectEndTime.Month - (SelectStartTime.Year * 12 + SelectStartTime.Month + _count) >= 0);
                                    if (list.Count > 0)
                                    {
                                        string csvfilepath = "";
                                        System.Windows.Application.Current.Dispatcher.Invoke(new Action(() =>
                                        {
                                            SaveFileDialog saveFileDialog = new SaveFileDialog();
                                            saveFileDialog.Filter = "CSV Files|*.csv";
                                            saveFileDialog.Title = "保存历史记录";
                                            if (saveFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                                            {
                                                csvfilepath = saveFileDialog.FileName;
                                            }
                                        }));
                                        if (csvfilepath != "")
                                        {
                                            using (var writer = new StreamWriter(new FileStream(csvfilepath, FileMode.Create), System.Text.Encoding.UTF8))
                                            using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
                                            {                                                
                                                csv.WriteRecords(list);
                                                MessageBox.Show($"保存{csvfilepath}完成", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        MessageBox.Show($"查询到{list.Count}条数据", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                    logger.Error(ex);
                                }
                            }
                            else
                            {
                                MessageBox.Show("数据库连接失败", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                logger.Error("数据库连接失败");
                            }
                            mysql1.DisConnect();
                        });
                        SelectRecordButtonIsEnabled = true;
                    }
                    break;
                default:
                    break;
            }
        }
        async void ExecuteSelectRecordCommand(object obj)
        {
            int airkind;
            switch (AirSelectedIndex)
            {
                case 1:
                    airkind = 2;
                    break;
                case 0:
                default:
                    airkind = 1;
                    break;
            }
            switch (obj.ToString())
            {
                case "0":
                    {
                        SelectRecordButtonIsEnabled = false;
                        await Task.Run(() =>
                        {
                            var mysql1 = new SXJ.Mysql(systemParam.MysqlIp);
                            if (mysql1.Connect())
                            {
                                try
                                {
                                    var instantFlowtmp = new PlotModel();
                                    instantFlowtmp.Legends.Add(new Legend
                                    {
                                        LegendPosition = LegendPosition.RightTop,
                                        LegendPlacement = LegendPlacement.Inside
                                    });
                                    var ls1 = new LineSeries { Title = "瞬时流量", Color = OxyColors.OrangeRed };
                                    var instantVelocitytmp = new PlotModel();
                                    instantVelocitytmp.Legends.Add(new Legend
                                    {
                                        LegendPosition = LegendPosition.RightTop,
                                        LegendPlacement = LegendPlacement.Inside
                                    });
                                    var ls2 = new LineSeries { Title = "瞬时流速", Color = OxyColors.MediumSpringGreen };
                                    var accumulateFlowtmp = new PlotModel();
                                    accumulateFlowtmp.Legends.Add(new Legend
                                    {
                                        LegendPosition = LegendPosition.RightTop,
                                        LegendPlacement = LegendPlacement.Inside
                                    });
                                    var ls3 = new LineSeries { Title = "累积流量", Color = OxyColors.MediumBlue };
                                    var instantTemperaturetmp = new PlotModel();
                                    instantTemperaturetmp.Legends.Add(new Legend
                                    {
                                        LegendPosition = LegendPosition.RightTop,
                                        LegendPlacement = LegendPlacement.Inside
                                    });
                                    var ls4 = new LineSeries { Title = "温度", Color = OxyColors.MediumVioletRed };
                                    int _count = 0;
                                    do
                                    {
                                        string str = $"SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'flowmeter{SelectStartTime.AddMonths(_count).ToString("yyyyMM")}';";
                                        DataSet ds = mysql1.Select(str);
                                        DataTable dt = ds.Tables[0];
                                        if (Convert.ToInt32(dt.Rows[0][0]) == 1)
                                        {
                                            str = $"SELECT * FROM flowmeter{SelectStartTime.AddMonths(_count).ToString("yyyyMM")} WHERE airkind = {airkind} AND created >= '{SelectStartTime:yyyy-MM-dd HH:mm:ss}' AND created <= '{SelectEndTime:yyyy-MM-dd HH:mm:ss}'";
                                            ds = mysql1.Select(str);
                                            dt = ds.Tables[0];
                                            if (dt.Rows.Count > 0)
                                            {
                                                for (int i = 0; i < dt.Rows.Count; i++)
                                                {
                                                    double x = DateTimeAxis.ToDouble(Convert.ToDateTime(dt.Rows[i]["created"]));
                                                    double y1 = Convert.ToDouble(dt.Rows[i]["instantflow"]);
                                                    ls1.Points.Add(new DataPoint(x, y1));
                                                    double y2 = Convert.ToDouble(dt.Rows[i]["instantvelocity"]);
                                                    ls2.Points.Add(new DataPoint(x, y2));
                                                    double y3 = Convert.ToDouble(dt.Rows[i]["accumulateflow"]);
                                                    ls3.Points.Add(new DataPoint(x, y3));
                                                    double y4 = Convert.ToDouble(dt.Rows[i]["instanttemperature"]);
                                                    ls4.Points.Add(new DataPoint(x, y4));
                                                }
                                            }
                                        }                                        
                                        _count++;
                                    } while (SelectEndTime.Year * 12 + SelectEndTime.Month - (SelectStartTime.Year * 12 + SelectStartTime.Month + _count) >= 0);
                                    instantFlowtmp.Series.Add(ls1);
                                    instantFlowtmp.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, StringFormat = "yyyy-MM-dd HH:mm:ss" });
                                    instantFlowtmp.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "FLOW" });
                                    HistoryInstantFlowPlotModel = instantFlowtmp;
                                    instantVelocitytmp.Series.Add(ls2);
                                    instantVelocitytmp.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, StringFormat = "yyyy-MM-dd HH:mm:ss" });
                                    instantVelocitytmp.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Velocity" });
                                    HistoryInstantVelocityPlotModel = instantVelocitytmp;
                                    accumulateFlowtmp.Series.Add(ls3);
                                    accumulateFlowtmp.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, StringFormat = "yyyy-MM-dd HH:mm:ss" });
                                    accumulateFlowtmp.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "FLOW" });
                                    HistoryAccumulateFlowPlotModel = accumulateFlowtmp;
                                    instantTemperaturetmp.Series.Add(ls4);
                                    instantTemperaturetmp.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, StringFormat = "yyyy-MM-dd HH:mm:ss" });
                                    instantTemperaturetmp.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Temperature" });
                                    HistoryInstantTemperaturePlotModel = instantTemperaturetmp;                                                                        
                                }
                                catch (Exception ex)
                                {
                                    MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                    logger.Error(ex);
                                }
                            }
                            else
                            {
                                MessageBox.Show("数据库连接失败", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                logger.Error("数据库连接失败");
                            }
                            mysql1.DisConnect();
                        });
                        SelectRecordButtonIsEnabled = true;
                    }
                    break;
                case "1":
                    {
                        SelectRecordButtonIsEnabled = false;
                        OpenFileDialog ofd = new OpenFileDialog();
                        ofd.Filter = "CSV文件(*.csv)|*.csv";
                        ofd.Multiselect = true;
                        ofd.Title = "选择CSV文件";
                        if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                        {
                            await Task.Run(() =>
                            {
                                try
                                {
                                    List<Record> csvRecords = new List<Record>();
                                    foreach (string file in ofd.FileNames)
                                    {
                                        using (var reader = new StreamReader(file))
                                        using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
                                        {
                                            var list1 = csv.GetRecords<Record>().ToList();
                                            foreach (var item in list1)
                                            {
                                                csvRecords.Add(item);
                                            }
                                        }
                                    }
                                    var airRecords = csvRecords.Where(t => t.气体类型 == airkind).ToList();
                                    MessageBox.Show($"加载到{airRecords.Count}条数据", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
                                    if (airRecords.Count > 0)
                                    {
                                        var instantFlowtmp = new PlotModel();
                                        instantFlowtmp.Legends.Add(new Legend
                                        {
                                            LegendPosition = LegendPosition.RightTop,
                                            LegendPlacement = LegendPlacement.Inside
                                        });
                                        var ls = new LineSeries { Title = "瞬时流量", Color = OxyColors.OrangeRed };
                                        for (int i = 0; i < airRecords.Count; i++)
                                        {
                                            double x = DateTimeAxis.ToDouble(airRecords[i].时间);
                                            double y = airRecords[i].瞬时流量;
                                            ls.Points.Add(new DataPoint(x, y));
                                        }
                                        instantFlowtmp.Series.Add(ls);
                                        instantFlowtmp.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, StringFormat = "yyyy-MM-dd HH:mm:ss" });
                                        instantFlowtmp.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "FLOW" });
                                        HistoryInstantFlowPlotModel = instantFlowtmp;

                                        var instantVelocitytmp = new PlotModel();
                                        instantVelocitytmp.Legends.Add(new Legend
                                        {
                                            LegendPosition = LegendPosition.RightTop,
                                            LegendPlacement = LegendPlacement.Inside
                                        });
                                        ls = new LineSeries { Title = "瞬时流速", Color = OxyColors.MediumSpringGreen };
                                        for (int i = 0; i < airRecords.Count; i++)
                                        {
                                            double x = DateTimeAxis.ToDouble(airRecords[i].时间);
                                            double y = airRecords[i].瞬时流速;
                                            ls.Points.Add(new DataPoint(x, y));
                                        }
                                        instantVelocitytmp.Series.Add(ls);
                                        instantVelocitytmp.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, StringFormat = "yyyy-MM-dd HH:mm:ss" });
                                        instantVelocitytmp.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Velocity" });
                                        HistoryInstantVelocityPlotModel = instantVelocitytmp;

                                        var accumulateFlowtmp = new PlotModel();
                                        accumulateFlowtmp.Legends.Add(new Legend
                                        {
                                            LegendPosition = LegendPosition.RightTop,
                                            LegendPlacement = LegendPlacement.Inside
                                        });
                                        ls = new LineSeries { Title = "累积流量", Color = OxyColors.MediumBlue };
                                        for (int i = 0; i < airRecords.Count; i++)
                                        {
                                            double x = DateTimeAxis.ToDouble(airRecords[i].时间);
                                            double y = airRecords[i].累积流量;
                                            ls.Points.Add(new DataPoint(x, y));
                                        }
                                        accumulateFlowtmp.Series.Add(ls);
                                        accumulateFlowtmp.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, StringFormat = "yyyy-MM-dd HH:mm:ss" });
                                        accumulateFlowtmp.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "FLOW" });
                                        HistoryAccumulateFlowPlotModel = accumulateFlowtmp;

                                        var instantTemperaturetmp = new PlotModel();
                                        instantTemperaturetmp.Legends.Add(new Legend
                                        {
                                            LegendPosition = LegendPosition.RightTop,
                                            LegendPlacement = LegendPlacement.Inside
                                        });
                                        ls = new LineSeries { Title = "温度", Color = OxyColors.MediumVioletRed };
                                        for (int i = 0; i < airRecords.Count; i++)
                                        {
                                            double x = DateTimeAxis.ToDouble(airRecords[i].时间);
                                            double y = airRecords[i].温度;
                                            ls.Points.Add(new DataPoint(x, y));
                                        }
                                        instantTemperaturetmp.Series.Add(ls);
                                        instantTemperaturetmp.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, StringFormat = "yyyy-MM-dd HH:mm:ss" });
                                        instantTemperaturetmp.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "Temperature" });
                                        HistoryInstantTemperaturePlotModel = instantTemperaturetmp;
                                    }
                                }
                                catch (Exception ex)
                                {
                                    MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                    logger.Error(ex);
                                }
                            });


                        }
                        SelectRecordButtonIsEnabled = true;
                    }
                    break;
                default:
                    break;
            }
        }
        void ExecuteSaveParamCommand()
        {
            if (MessageBox.Show($"确认保存参数吗？", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
            {
                systemParam.RemoteFilePath = RemoteFilePath;
                for (int i = 0; i < systemParam.AirArray.Length; i++)
                {
                    systemParam.AirScale[i] = ScaleItems[i].Scale;
                }
                string jsonString = JsonConvert.SerializeObject(systemParam, Formatting.Indented);
                File.WriteAllText(System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "SystemParam.json"), jsonString);
                MessageBox.Show("保存完成", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
        void ExecuteFilePathSelectCommand(object obj)
        {
            using (var fbd = new FolderBrowserDialog())
            {
                System.Windows.Forms.DialogResult result = fbd.ShowDialog();
                if (result == System.Windows.Forms.DialogResult.OK && !string.IsNullOrWhiteSpace(fbd.SelectedPath))
                {
                    switch (obj.ToString())
                    {
                        case "0":
                            RemoteFilePath = fbd.SelectedPath;
                            break;
                        default:
                            break;
                    }
                }
            }
        }
        async void ExecuteAppLoadedEventCommand()
        {
            AirComboBoxSelectedIndex = 0;
            Air = new AirKind() { Name = systemParam.AirArray[0], State = true };
            try
            {
                if (!Directory.Exists(systemParam.RemoteFilePath))
                {
                    Directory.CreateDirectory(systemParam.RemoteFilePath);
                }
                RemoteFilePathState = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                RemoteFilePathState = false;
                logger.Error(ex);
            }
            SerialPortState = ModbusRTU.Instance.Connect(systemParam.ModbusCOM);

            await Task.Run(() =>
            {
                if (mysql.Connect())
                {
                    try
                    {
                        string str = "SELECT NOW()";
                        DataSet ds = mysql.Select(str);
                        DataTable dt = ds.Tables[0];
                        if (dt.Rows.Count > 0)
                        {
                            logger.Info($"数据库连接成功{dt.Rows[0][0]}");
                            DataBaseState = true;
                        }
                        else
                        {
                            DataBaseState = false;
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        logger.Error(ex);
                        DataBaseState = false;
                    }

                }
                else
                {
                    MessageBox.Show("数据库连接失败", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    logger.Error("数据库连接失败");
                    DataBaseState = false;
                }
                mysql.DisConnect();
            });

            logger.Info("软件加载完成");
            Run();
        }
        void ExecuteAppClosedEventCommand()
        {
            ModbusRTU.Instance.DisConnect();
            mysql.DisConnect();
            logger.Info("软件退出");
        }
        void ExecuteMenuCommand(object obj)
        {
            switch (obj.ToString())
            {
                case "0":
                    RealTimePageVisibility = "Visible";
                    ParameterPageVisibility = "Collapsed";
                    HistoryPageVisibility = "Collapsed";
                    break;
                case "2":
                    RealTimePageVisibility = "Collapsed";
                    ParameterPageVisibility = "Collapsed";
                    HistoryPageVisibility = "Visible";
                    break;
                case "3":
                    RealTimePageVisibility = "Collapsed";
                    ParameterPageVisibility = "Visible";
                    HistoryPageVisibility = "Collapsed";
                    break;
                case "4":
                    /*
                    if (mysql.Connect())
                    {
                        try
                        {
                            string str = $@"CREATE TABLE IF NOT EXISTS `flowmeter{DateTime.Now.ToString("yyyyMM")}` (
`id` bigint NOT NULL AUTO_INCREMENT,
`instantflow` double NOT NULL COMMENT '瞬时流量',
`instantvelocity` double NOT NULL COMMENT '瞬时流速',
`accumulateflow` double NOT NULL COMMENT '累积流量',
`instanttemperature` double NOT NULL COMMENT '温度',
`created` datetime NOT NULL,
`airkind` int NOT NULL COMMENT '气体类型',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;";
                            mysql.executeQuery(str);
                        }
                        catch (Exception ex)
                        {
                            DataBaseState = false;
                            logger.Error(ex);
                        }
                    }
                    mysql.DisConnect();
                       */
                    //ushort[] r = new ushort[3] { 1,2,3};
                    //var aa = string.Join("", from p in r select p.ToString("X4"));
                    break;

                default:
                    break;
            }
        }
        #endregion
        #region 构造函数
        public MainWindowViewModel()
        {
            ScaleItems = new ObservableCollection<ScaleItem>();
            NlogConfig();
            PlotModel1.Series.Add(new LineSeries { LineStyle = LineStyle.Solid, Color = OxyColors.SpringGreen, MarkerType = MarkerType.Circle, MarkerSize = 5, MarkerStroke = OxyColors.Black, MarkerFill = OxyColors.Transparent, MarkerStrokeThickness = 4 });

            PlotModel1.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, IsZoomEnabled = false, MajorGridlineStyle = LineStyle.Dot, Title = "时间", TitleFontSize = 16, StringFormat = "HH:mm:ss" });
            PlotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, IsZoomEnabled = false, MajorGridlineStyle = LineStyle.Dot, Title = "FLOW", TitleFontSize = 16, Minimum = -10, Maximum = 200 });

            PlotModel2.Series.Add(new LineSeries { LineStyle = LineStyle.Solid, Color = OxyColors.Violet, MarkerType = MarkerType.Circle, MarkerSize = 5, MarkerStroke = OxyColors.Black, MarkerFill = OxyColors.Transparent, MarkerStrokeThickness = 4 });
            PlotModel2.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, IsZoomEnabled = false, MajorGridlineStyle = LineStyle.Dot, Title = "时间", TitleFontSize = 16, StringFormat = "HH:mm:ss" });
            PlotModel2.Axes.Add(new LinearAxis { Position = AxisPosition.Left, IsZoomEnabled = false, MajorGridlineStyle = LineStyle.Dot, Title = "Velocity", TitleFontSize = 16, Minimum = -10, Maximum = 100 });

            LoadParam();
            ModbusRTU.Instance.MessagePrintEvent += Instance_MessagePrintEvent;
            mysql = new SXJ.Mysql(systemParam.MysqlIp);
            SelectEndTime = DateTime.Now;
            SelectStartTime = DateTime.Now.AddDays(-1);
            for (int i = 0; i < systemParam.AirArray.Length && i < systemParam.AirScale.Length; i++)
            {
                ScaleItems.Add(new ScaleItem() { 
                    Name = systemParam.AirArray[i],
                    Scale = systemParam.AirScale[i]
                });
            }
        }
        #endregion
        #region 功能函数
        private void Instance_MessagePrintEvent(object sender, string message)
        {
            logger.Info($"{sender}:{message}");
        }
        private void LoadParam()
        {
            try
            {
                //Json序列化，从文件读取
                string jsonString = File.ReadAllText(System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "SystemParam.json"));
                systemParam = JsonConvert.DeserializeObject<SystemParam>(jsonString);
                RemoteFilePath = systemParam.RemoteFilePath;
            }
            catch (Exception ex)
            {
                logger.Error(ex);
                MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Environment.Exit(-1);
            }
        }
        public async void Run()
        {
            int lastHour = DateTime.Now.Hour;
            //Random rdy = new Random();
            int recordCount = 0;
            while (true)
            {
                try
                {
                    if (SerialPortState)
                    {
                        for (int i = 0; i < systemParam.AirArray.Length; i++)
                        {
                            try
                            {
                                //采集
                                string str1 = await Task.Run(() => { return ModbusRTU.Instance.ReadAsHexString((byte)(i + 1), 0x0000, 14); });

                                string instantflowstr = str1.Substring(4, 4) + str1.Substring(0, 4);//2个字是瞬时流量;高低位取反2143
                                float instantflow = GetFloatValueFromHexString(instantflowstr);
                                string instantvelocitystr = str1.Substring(12, 4) + str1.Substring(8, 4);//2个字是瞬时流速;
                                float instantvelocity = GetFloatValueFromHexString(instantvelocitystr);
                                string accumulateflowstr = str1.Substring(44, 4) + str1.Substring(40, 4);//2个字是累积流量;
                                float accumulateflow = GetFloatValueFromHexString(accumulateflowstr);
                                accumulateflow *= systemParam.AirScale[i];
                                string temperaturestr = str1.Substring(52, 4) + str1.Substring(48, 4);//2个字是温度;
                                float temperature = GetFloatValueFromHexString(temperaturestr);

                                if (i == AirComboBoxSelectedIndex)
                                {
                                    InstantFlow = instantflow;
                                    CreateTime = DateTime.Now;
                                    InstantVelocity = instantvelocity;
                                    AccumulateFlow = accumulateflow;
                                    Temperature = temperature;
                                    Air.State = true;
                                    lock (plotModelLockObject)
                                    {
                                        var s = (LineSeries)PlotModel1.Series[0];
                                        if (s.Points.Count >= 10)
                                        {
                                            s.Points.RemoveAt(0);
                                        }
                                        //double y = ArFlowValue = ArInstantFlow= rdy.Next(1000);
                                        double y = instantflow;
                                        var xt = DateTime.Now;
                                        s.Points.Add(new DataPoint(DateTimeAxis.ToDouble(xt), y));
                                        PlotModel1.InvalidatePlot(true);

                                        var s2 = (LineSeries)PlotModel2.Series[0];
                                        if (s2.Points.Count >= 10)
                                        {
                                            s2.Points.RemoveAt(0);
                                        }
                                        //double y2 = ArVelocityValue = ArInstantVelocity = rdy.Next(100) / 1000.0;
                                        double y2 = instantvelocity;
                                        s2.Points.Add(new DataPoint(DateTimeAxis.ToDouble(xt), y2));
                                        PlotModel2.InvalidatePlot(true);
                                    }
                                }

                                if (recordCount == 0)//5分钟，产生1条记录。
                                {
                                    await Task.Run(() =>
                                    {
                                        if (mysql.Connect())
                                        {
                                            try
                                            {
                                                string tablename = $"flowmeter{DateTime.Now.ToString("yyyyMM")}";
                                                string str = $@"CREATE TABLE IF NOT EXISTS `{tablename}` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `instantflow` double NOT NULL COMMENT '瞬时流量',
  `instantvelocity` double NOT NULL COMMENT '瞬时流速',
  `accumulateflow` double NOT NULL COMMENT '累积流量',
  `instanttemperature` double NOT NULL COMMENT '温度',
  `created` datetime NOT NULL,
  `airkind` int NOT NULL COMMENT '气体类型',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;";
                                                mysql.executeQuery(str);


                                                str = $"INSERT INTO {tablename}  (instantflow,instantvelocity,accumulateflow,instanttemperature,created,airkind) VALUES ({instantflow:F3},{instantvelocity:F4},{accumulateflow:F3},{temperature:F2},'{DateTime.Now:yyyy-MM-dd HH:mm:ss}',{i + 1})";
                                                mysql.executeQuery(str);
                                                DataBaseState = true;
                                            }
                                            catch (Exception ex)
                                            {
                                                DataBaseState = false;
                                                logger.Error(ex);
                                            }
                                        }
                                        mysql.DisConnect();
                                    });
                                }
                   
                            }
                            catch (Exception ex)
                            {
                                if (i == AirComboBoxSelectedIndex)
                                {
                                    Air.State = false;
                                }
                                logger.Error(ex);
                            }
                        }
                    }
                    //自动备份
                    if (lastHour != DateTime.Now.Hour)
                    {
                        lastHour = DateTime.Now.Hour;
                        await Task.Run(() =>
                        {
                            var mysql1 = new SXJ.Mysql(systemParam.MysqlIp);
                            if (mysql1.Connect())
                            {
                                try
                                {
                                    string tablename = $"flowmeter{DateTime.Now.ToString("yyyyMM")}";
                                    string str = $"SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = '{tablename}';";
                                    DataSet ds = mysql1.Select(str);
                                    DataTable dt = ds.Tables[0];
                                    if (Convert.ToInt32(dt.Rows[0][0]) == 1)
                                    {
                                        str = $"SELECT * FROM {tablename} WHERE created > '{DateTime.Now.AddHours(-1):yyyy-MM-dd HH:mm:ss}' AND created <= '{DateTime.Now:yyyy-MM-dd HH:mm:ss}'";
                                        ds = mysql1.Select(str);
                                        dt = ds.Tables[0];
                                        if (dt.Rows.Count > 0)
                                        {
                                            string csvfilepath = Path.Combine(systemParam.RemoteFilePath, $"{DateTime.Now:yyyyMMddHHmmss}.csv");
                                            using (var writer = new StreamWriter(new FileStream(csvfilepath, FileMode.Create), System.Text.Encoding.UTF8))
                                            using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
                                            {
                                                List<Record> list = new List<Record>();
                                                for (int i = 0; i < dt.Rows.Count; i++)
                                                {

                                                    list.Add(new Record
                                                    {
                                                        瞬时流量 = Convert.ToDouble(dt.Rows[i]["instantflow"]),
                                                        瞬时流速 = Convert.ToDouble(dt.Rows[i]["instantvelocity"]),
                                                        累积流量 = Convert.ToDouble(dt.Rows[i]["accumulateflow"]),
                                                        温度 = Convert.ToDouble(dt.Rows[i]["instanttemperature"]),
                                                        时间 = Convert.ToDateTime(dt.Rows[i]["created"]),
                                                        气体类型 = Convert.ToInt32(dt.Rows[i]["airkind"])
                                                    });
                                                }
                                                csv.WriteRecords(list);
                                                RemoteFilePathState = true;
                                                logger.Info($"备份数据到文件{csvfilepath}");
                                            }
                                        }
                                    }                                      
                                }
                                catch (Exception ex)
                                {
                                    RemoteFilePathState = false;
                                    logger.Error(ex);
                                }
                            }
                            else
                            {
                                logger.Error("数据库连接失败");
                            }
                            mysql1.DisConnect();
                        });
                    }
                }
                catch (Exception ex)
                {
                    logger.Error(ex);
                }
                if (recordCount++ > 60 * 5)
                {
                    recordCount = 0;
                }
                await Task.Delay(1000);
            }
        }
        private float GetFloatValueFromHexString(string hex)
        {
            //2143
            //string hex = "41F8BA4A";
            //string hex = "4036821F";
            byte[] raw = new byte[hex.Length / 2];
            for (int i = 0; i < raw.Length; i++)
            {
                // THEN DEPENDING ON ENDIANNESS
                //raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
                // OR
                raw[raw.Length - i - 1] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
            }
            float f = BitConverter.ToSingle(raw, 0);
            return f;
        }
        private void NlogConfig()
        {
            var config = new NLog.Config.LoggingConfiguration();

            // Targets where to log to: File and Console
            var logfile = new NLog.Targets.FileTarget("logfile") { FileName = "${basedir}/logs/${shortdate}.log", Layout = "${longdate}|${level:uppercase=true}|${message}" };
            var logconsole = new NLog.Targets.ConsoleTarget("logconsole");

            // Rules for mapping loggers to targets            
            config.AddRule(LogLevel.Info, LogLevel.Fatal, logconsole);
            config.AddRule(LogLevel.Debug, LogLevel.Fatal, logfile);

            // Apply config           
            NLog.LogManager.Configuration = config;
        }
        #endregion       
    }
    public class Record
    {
        public double 瞬时流量 { get; set; }
        public double 瞬时流速 { get; set; }
        public double 累积流量 { get; set; }
        public double 温度 { get; set; }
        public DateTime 时间 { get; set; }
        public int 气体类型 { get; set; }
    }
    public class AirKind : BindableBase
    {
        private string name;
        public string Name
        {
            get { return name; }
            set { SetProperty(ref name, value); }
        }
        private bool state;
        public bool State
        {
            get { return state; }
            set { SetProperty(ref state, value); }
        }
    }
    public class ScaleItem
    {
        public string Name { get; set; }
        public float Scale { get; set; }
    }
}
